module ext.ws2812;

/**
* 手册中秒速的 800k,是一个周期的时间,而不是一个周期的速度,所以实际速度是 800k/24 = 33.3k
* 也就是说,每个周期内,需要发送24个bit,每个bit的时间是 1/33.3k = 30us
* 同时要求IO翻转速度不能大于这个800k,如果大于这个速度,那么就会出现翻转的时候,数据还没有发送完毕的情况
* 误动作会出现,位与下一个位之间间隔不能过小,两个上升沿之间的间隔不能过小,
*/

import arm;
//import chipconf;

import arm.utils;
import arm.builtins:__nop;
//import core.bitop;
//import ldc.llvmasm;


union GRB_Type
{
    uint value;
    alias value this;
    struct 
    {
        ubyte Blue;
        ubyte Red;
        ubyte Green;
    } 
}

/**
* 端口模拟方式实现控制,(84mhz频率下完成测试)
* 程序空间换执行速度模式
*Params: 
*  mPin = 引脚接口
* mLength= 点位数量
*/
static interface IWS2812_Soft(alias mPin,size_t mLength) if(mPin.IsPin)
{
    import arm.rcc;
    
    struct WStatus{
        uint    update:1;       /// 有数据更新
    }

    static assert(mLength,"mLength must > 0");
    enum mPinSet = cast(uint*)mPin.BitBand_Set;
    enum mPinClr = cast(uint*)mPin.BitBand_Clr;
    /// nop占用时间 单位 ns
    enum NOPTime = 1_000_000_000/SystemClockFreq + (((1_000_000_000%SystemClockFreq) > 5) ? 1 : 0);
    enum gDelay = 200;
    enum ResDelay = 200;

    ///  低电平长度修正,因为涉及到循环时的执行时间,这个参数需要适当修正
    enum Low_fix1 = 10;

    enum LowDelay = 336/NOPTime;

    enum T0HDelay = 220/NOPTime - 2;
    enum T0LDelay = 580/NOPTime - Low_fix1;
    /// 1调用前导约 27个周期,测算结果
    enum T1HDelay = 580/NOPTime - 2;
    /// 0调用前导约 ???
    enum T1LDelay = 580/NOPTime - Low_fix1;

    /// 静态检查参数,避免主频过低导致的错误
    static assert(T0LDelay > 0,"T1LDelay must > 0");
    static assert(T1LDelay > 0,"T1LDelay must > 0");
    static assert(LowDelay > 0,"LowDelay must > 0");
    static assert(T0HDelay > 0,"T0HDelay must > 0");
    static assert(T1HDelay > 0,"T1HDelay must > 0");





    /// 缓冲区
    __gshared static GRB_Type[mLength] mBuffer = GRB_Type.init;
    /// 更新状态
    __gshared static WStatus mStatus;
    /**
    * 设点位颜色
    *Params: 
    *  
    */
    static void SetPoint(size_t idx,GRB_Type data)
    {
        mStatus.update = 1;
        mBuffer[idx] = data;

    };

    static void SetPoint(size_t idx,ubyte Red,ubyte Green,ubyte Blue)
    {
        //import std.bitmanip:revers
        mStatus.update = 1;
        mBuffer[idx].Red = Red;
        mBuffer[idx].Green = Green;
        mBuffer[idx].Blue = Blue;

    }
    /+
    /**
    * 刷新输出
    * 未考虑执行连贯性,未禁止中断
    */
    static void Update(bool force = false)
    {
        import arm.misc:combineMasks;
        enum gDelay = 200;
        enum ResDelay = 200;
        enum LowDelay = 45;
        enum T0HDelay = 15;
        enum T1HDelay = 50;

        if(!mStatus.update && !force) return ;
        scope(exit) mStatus.update = 0;
        // 初始延时
        *mPinClr = 1;       // 设置低电平
        //auto ptr = cast(ubyte*)mBuffer.ptr;
        auto maxl = mBuffer.length;
        ubyte tmp = 0x00;
        for(int i;i<maxl;i++)
        {
            tmp = mBuffer[i];
            static foreach_reverse(si;1..8)
            {
                *mPinSet = 1;
                if( tmp & combineMasks!(si)){
                    //*mPinSet = 1;
                    static foreach(delay_i;0..T1HDelay) __nop();
                    
                }else{
                    //*mPinSet = 1;
                    static foreach(delay_i;0..T0HDelay) __nop();
                }
                *mPinClr = 1;
                static foreach(delay_i;0..LowDelay) __nop();
            }
            /// 手动补偿循环末尾
            if(tmp & 1){
                *mPinSet = 1;
                static foreach(delay_i;0..T1HDelay) __nop();
            }else{
                *mPinSet = 1;
                static foreach(delay_i;0..T0HDelay) __nop();
            }
            *mPinClr = 1;
            static foreach(delay_i;0..12) __nop();
        }
        static foreach(delay_i;0..20) __nop();
        *mPinSet = 1;
        __nop();
        *mPinClr = 1;
        //Utils.DelayNOP(ResDelay);

    }
    +/
    /**
    * 初始化缓冲区
    */
    static void Init()
    {
        //mBuffer[] = GRB_Type(0,0,0);
        //mStatus.update = 1;
        import baremetal.stdlib;
        //memset(&mBuffer[0],0xff,mBuffer.length*GRB_Type.sizeof);
        memsetD(mBuffer,0x00);

        Update2(true);
        
    }
    pragma(inline,true)
    static void Txx(size_t hdelay,size_t ldelay)()
    {
        *mPinSet = 1;
        static foreach(delay_i;0..hdelay) __nop();
        *mPinClr = 1;
        static foreach(delay_i;0..ldelay) __nop();
    }

    // 
    static void Update2(bool force = false)
    {
        enum WS2812_Width = 24;
        enum WS2812_RGB_Width = 3;


        if(!mStatus.update && !force) return ;
        scope(exit) mStatus.update = 0;
        *mPinClr = 1;
        uint Sel;
        uint* psel;

        foreach(i;0..mBuffer.length)
        {
            //auto pSel = cast(uint*)&mBuffer[i/WS2812_RGB_Width];
            psel = cast(uint*)&mBuffer[i];
            //Sel = mBuffer[i].value;
            foreach_reverse(j;1..WS2812_Width)
            {
                //*mPinSet = 1;
                if( *psel & (1 << (j))){
                    Txx!(T1HDelay,T1LDelay)();
                }else{
                    Txx!(T0HDelay,T0LDelay)();
                }
            }
            // 发送最后一个数据位,改为手动补偿
            if( *psel & 1){
                Txx!(T1HDelay,T1LDelay-10)();
            }else{
                Txx!(T0HDelay,T0LDelay-10)();
            }
        }
        
        *mPinSet = 1;
        static foreach(delay_i1;0..1) __nop();
        *mPinClr = 1;
    }
}

/**
* 以IO口模拟操作
* 适合低主频使用的方案,以存储`flash`固定执行代码减少位查询比对
*Params:
* mPin = 引脚定义
* Led[],数组形式输出
* todo: 未写具体代码,预计采用混入模板实现
*/
static interface IWS2812_Static(alias mPin,LED...) if(mPin.IsPin)
{

}